package com.cskaoyan.javase.array._6call;

import java.util.Arrays;

/**
 * 什么是方法的传值问题？
 * 调用方法时，我们需要传递实参给方法，在方法内部有可能会改变这些实参的值。
 * 那么方法执行完毕后，这些实参的值在原先的方法中会怎么变呢？这就是方法的传值问题。
 *
 * 接下来了解方法的两种传值方式，它们是用于解释方法传参的两个概念：
 *      1.值传递（call by value）
 *          指的是调用方法时，传入的是实参的拷贝而不是实参本身。
 *          如果Java是值传递的，那么方法改变的是实参拷贝的值
 *          原本实参的值是不会被改变的。
 *
 *      2.引用传递（call by reference）
 *          指的是调用方法时，传入的是实参变量的地址，也就是实参本身。
 *          如果Java是引用传递的，方法改变的是实参本身的值
 *              方法结束后，原本实参变量的值会随直改变。
 *
 * Java方法调用的传值方式,是非常重要,非常基础的知识点
 * 所有的Java程序员都应该明确知道Java方法的传值方式
 *
 *
 *  写代码测试一下:
 *  1.如果传入方法的参数是一个基本数据类型,测试发现,方法不能够修改实参变量的取值
 *      所以至少对于Java基本数据类型实参变量而言,Java是值传递的.
 *
 *  2.如果传入方法的参数是一个引用数据类型(方法需要传入引用数据类型,实际上是需要传入对象,我们可以选择传入一个引用)
 *      测试发现,方法可以修改实参对象中元素的取值
 *      所以至少对于Java引用数据类型实参变量而言,Java是引用传递的.
 *
 *    综上,Java基本数据类型参数是值传递,引用数据类型参数是引用传递
 *
 * 以上结论是非常典型的错误,是没有弄清楚方法调用的本质,实际上Java没有任何引用传递
 * Java实际上只有值传递.
 *
 * 明确了Java的值传递后,对于我们调用方法,实现需求时,有什么意义呢?有什么结论呢?
 * Java的方法到底能够对传入的实参变量,做什么呢?
 * 结论:
 *      1.任何Java方法,都不可能修改另外一个方法中的局部变量,包括:
 *          a.基本数据类型变量
 *          b.引用数据类型的引用
 *      这种修改都是不可能的,违背了局部变量的设计原则.
 *
 *      2.(重点)Java方法可以修改对象的状态,因为得到了引用的拷贝,仍然指向原先实参引用指向的对象
 *
 * @since 14:12
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        int num = 10;
        doubleIntValue(num);
        System.out.println(num);

        int[] arr = {1, 2, 3};
        doubleIntArrElement(arr);
        System.out.println(Arrays.toString(arr));

        System.out.println("----------------------");
        int[] arr1 = {666, 666, 666};
        int[] arr2 = {777, 777, 777};
        System.out.println("swap方法调用之前的arr1:" + Arrays.toString(arr1));
        System.out.println("swap方法调用之前的arr2:" + Arrays.toString(arr2));
        swapIntArrReference(arr1, arr2);
        /*
            假如Java是值传递,方法得到的是引用的拷贝,那么方法中交换的就是引用的拷贝
                对于原先的实参引用来说,交换失败!

            假如Java是引用传递,方法得到的是引用本身,交换就是实参中的引用
                那么交换应该成功!

            实际上这个交换是失败的,所以Java只有值传递,没有任何引用传递!!
         */
        System.out.println("swap方法调用之后的arr1:" + Arrays.toString(arr1));
        System.out.println("swap方法调用之后的arr2:" + Arrays.toString(arr2));
    }

    // 交换两个数组的引用
    public static void swapIntArrReference(int[] arr1, int[] arr2) {
        int[] temp = arr1;
        arr1 = arr2;
        arr2 = temp;

        System.out.println("swap方法调用中的arr1:" + Arrays.toString(arr1));
        System.out.println("swap方法调用中的arr2:" + Arrays.toString(arr2));
    }

    // 二倍数组的元素
    public static void doubleIntArrElement(int[] arr) {
        for (int i = 0; i < arr.length; i++) {
            arr[i] *= 2;
        }
    }

    // 将方法传入的int参数变为原先的二倍
    public static void doubleIntValue(int num) {
        num *= 2;
    }
}
